"use strict";
var __spreadArrays = (this && this.__spreadArrays) || function () {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
    for (var r = Array(s), k = 0, i = 0; i < il; i++)
        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
            r[k] = a[j];
    return r;
};
var Vue = /** @class */ (function () {
    function Vue(options) {
        //this.$el $data
        this.$el = options.el; //模板
        this.$data = options.data || {}; //数据
        if (this.$el) {
            //数据劫持
            new Observer(this.$data);
            //进行模板编译，最终把数据展示到页面上
            new Complie(this.$el, this);
        }
    }
    return Vue;
}());
//发布订阅
var Dep = /** @class */ (function () {
    function Dep() {
        this.watchers = [];
    }
    Dep.prototype.addWatch = function (watch) {
        //订阅观察者
        this.watchers.push(watch);
    };
    Dep.prototype.notify = function () {
        //发布
        this.watchers.forEach(function (watch) { return watch.update(); });
    };
    Dep.target = null;
    return Dep;
}());
//观察者模式   观察者  被观察者
var Watcher = /** @class */ (function () {
    function Watcher(vm, expr, cb) {
        this.vm = vm;
        this.expr = expr;
        this.cb = cb;
        //默认先存放老值
        this.oldValue = this.get();
    }
    Watcher.prototype.get = function () {
        Dep.target = this;
        var value = compileUtil.getVal(this.expr, this.vm);
        Dep.target = null;
        return value;
    };
    Watcher.prototype.update = function () {
        var newVal = compileUtil.getVal(this.expr, this.vm);
        if (newVal != this.oldValue) {
            this.cb(newVal);
        }
    };
    return Watcher;
}());
// vm.$watch(vm,'school.name',(newValue) => {
// })
//实现数据劫持
var Observer = /** @class */ (function () {
    function Observer(data) {
        this.observer(data);
    }
    Observer.prototype.observer = function (data) {
        //如果是对象才观察
        if (data && typeof data === 'object') {
            for (var key in data) {
                this.defineReactive(data, key, data[key]);
            }
        }
    };
    Observer.prototype.defineReactive = function (obj, key, value) {
        var _this = this;
        this.observer(value);
        var dep = new Dep();
        Object.defineProperty(obj, key, {
            get: function () {
                Dep.target && dep.addWatch(Dep.target);
                return value;
            },
            set: function (newValue) {
                if (newValue != value) {
                    _this.observer(value);
                    value = newValue;
                    //通知每个watcher
                    dep.notify();
                }
            }
        });
    };
    return Observer;
}());
var compileUtil = {
    getVal: function (expr, vm) {
        return expr.split('.').reduce(function (data, current) {
            return data[current];
        }, vm.$data);
    },
    setValue: function (vm, expr, data) {
        expr.split('.').reduce(function (prev, current, index, arr) {
            if (index === arr.length - 1) {
                return prev[current] = data;
            }
            return prev[current];
        }, vm.$data);
    },
    model: function (node, expr, vm) {
        var _this = this;
        var fn = this.update.modelUpdate;
        var value = this.getVal(expr, vm);
        new Watcher(vm, expr, function (newVal) {
            fn(node, newVal);
        });
        fn(node, value);
        node.addEventListener('input', function (e) {
            var data = e.target.value;
            _this.setValue(vm, expr, data);
        });
    },
    text: function (node, expr, vm) {
        var _this = this;
        var content = expr.replace(/\{\{(.+?)\}\}/g, function () {
            var args = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                args[_i] = arguments[_i];
            }
            new Watcher(vm, args[1], function (newValue) {
                fn(node, newValue);
            });
            return _this.getVal(args[1], vm);
        });
        var fn = this.update.textUpdate;
        fn(node, content);
    },
    update: {
        modelUpdate: function (node, valueData) {
            //<input value="八维教育" /> 
            node.value = valueData;
        },
        textUpdate: function (node, contentData) {
            // {{school}} = “八维教育”
            node.textContent = contentData;
        }
    }
};
//编译
var Complie = /** @class */ (function () {
    function Complie(el, vm) {
        this.vm = vm;
        //元素节点  字符串
        this.el = this.isElementNode(el) ? this.el : document.querySelector(el);
        //把所有的元素放到内存中
        var fragment = this.nodeToFragment(this.el);
        // console.log(fragment);
        //编辑模板，数据
        this.compile(fragment);
        this.el.appendChild(fragment);
    }
    //判断属性是否是指令
    Complie.prototype.isDirective = function (attr) {
        // console.log(attr)
        return attr.startsWith('v-');
    };
    //编译元素节点
    Complie.prototype.compileElement = function (node) {
        var _this = this;
        var attributes = node.attributes;
        __spreadArrays(attributes).forEach(function (attr) {
            var name = attr.name, expr = attr.value;
            if (_this.isDirective(name)) {
                //是指令才替换  model html text
                // console.dir(attr);
                var _a = name.split('-'), directive = _a[1];
                compileUtil[directive](node, expr, _this.vm);
            }
        });
    };
    //编译文本节点
    Complie.prototype.compileText = function (node) {
        // console.log(node);
        var content = node.textContent;
        if (/\{\{(.+?)\}\}/.test(content)) {
            compileUtil['text'](node, content, this.vm);
        }
    };
    //编译的方法
    Complie.prototype.compile = function (node) {
        var _this = this;
        // console.log(node.childNodes)
        var childNodes = node.childNodes;
        __spreadArrays(childNodes).forEach(function (child) {
            // console.log(child)
            if (_this.isElementNode(child)) {
                //元素节点
                _this.compileElement(child);
                _this.compile(child);
            }
            else {
                //文本节点
                _this.compileText(child);
            }
        });
    };
    Complie.prototype.nodeToFragment = function (node) {
        //createDocumentFragment:创建一个新的空白的文档片段
        var fragment = document.createDocumentFragment();
        var firstChild;
        // console.dir(node);
        while (firstChild = node.firstChild) {
            // console.log("======");
            fragment.appendChild(firstChild);
        }
        return fragment;
    };
    Complie.prototype.isElementNode = function (node) {
        //nodeType返回节点的类型  1:元素节点  2：属性节点  3：文本节点  8：注释节点
        return node.nodeType === 1;
    };
    return Complie;
}());
